#include <vector>
#include <semaphore.h>
#include <pthread.h>



template <class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t& lock)
    {
        pthread_mutex_lock(&lock);
    }

    void Unlock(pthread_mutex_t& lock)
    {
        pthread_mutex_unlock(&lock);
    }    
public:
    RingQueue(int cap = 5)
    :rq_(cap), cap_(cap), c_step_(0), p_step_(0)
    {
        sem_init(&c_data_sem_,0,0);//第二个参数表示是否共享，第三个参数表示初始化的值
        //对于消费者来说，初始值设为0，表示等待生产者生产后才能消费
        sem_init(&p_space_sem_,0,cap);

        pthread_mutex_init(&c_mutex_, nullptr);
        pthread_mutex_init(&p_mutex_, nullptr);
    }

    ~RingQueue()
    {
        //对信号量进行释放
        sem_destroy(&c_data_sem_);
        sem_destroy(&p_space_sem_);

        //对锁进行释放
        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }

    void Push(T& in)//生产
    {
        //进行PV操作，并维持环形队列结构
        P(p_space_sem_);

        Lock(p_mutex_);
        rq_[p_step_]= in;//生产
        //维持环形队列结构
        p_step_++;
        p_step_ %= cap_; 
        Unlock(p_mutex_);

        V(c_data_sem_);



    }

    void Pop(T* out)//消费
    {
        //进行PV操作，并维持环形队列结构
        P(c_data_sem_);

        Lock(c_mutex_);
        *out = rq_[c_step_];//消费
        //维持环形队列结构
        c_step_++;
        c_step_ %= cap_;  
        Unlock(c_mutex_);
        
        V(p_space_sem_);

    }

private:
    std::vector<T> rq_;//环形队列
    int cap_;//表示容量

    int c_step_;//消费者下标
    int p_step_;//生产者下标

    sem_t c_data_sem_;//消费者关注的资源
    sem_t p_space_sem_;//生产者关心的资源

    //需要加两把锁保护临界区资源
    pthread_mutex_t c_mutex_;
    pthread_mutex_t p_mutex_;
};